/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.caching.setting;

import io.iec.edp.caf.caching.api.RedisDataSerializer;
import io.iec.edp.caf.caching.serializer.DefaultJsonSerializer;
import io.iec.edp.caf.commons.utils.InvokeService;
import io.iec.edp.caf.commons.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

/**
 * 二级缓存配置项
 */
public class SecondaryCacheSetting implements Serializable {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 缓存有效时间
     */
    private long expiration = 5;

    /**
     * 缓存主动在失效前强制刷新缓存的时间
     */
    private long preloadTime = 1;

    /**
     * 时间单位 {@link TimeUnit}
     */
    private TimeUnit timeUnit = TimeUnit.MINUTES;

    /**
     * 是否强制刷新（走数据库），默认是false
     */
    private boolean forceRefresh = false;

    /**
     * 是否使用缓存名称作为 redis key 前缀
     */
    private boolean usePrefix = true;

    /**
     * 非空值和null值之间的时间倍率，默认是1。allowNullValue=true才有效
     * <p>
     * 如配置缓存的有效时间是200秒，倍率这设置成10，
     * 那么当缓存value为null时，缓存的有效时间将是20秒，非空时为200秒
     * </p>
     */
    private int magnification = 10;

    /**
     * 默认的Redis序列化器
     * 底层redis只接受String类型 因此需要在cache层把object数据转为string类型
     */
    private RedisDataSerializer redisDataSerializer = new DefaultJsonSerializer();

    public SecondaryCacheSetting() {
    }

    /**
     * @param expiration     缓存有效时间
     * @param preloadTime    缓存刷新时间
     * @param timeUnit       时间单位 {@link TimeUnit}
     * @param forceRefresh   是否强制刷新
     * @param magnification  非空值和null值之间的时间倍率
     * @param serializerType 默认序列化器
     */
    public SecondaryCacheSetting(long expiration, long preloadTime, TimeUnit timeUnit, boolean forceRefresh, int magnification, String serializerType) {
        this.expiration = expiration;
        this.preloadTime = preloadTime;
        this.timeUnit = timeUnit;
        this.forceRefresh = forceRefresh;
        this.magnification = magnification;
        this.usePrefix = true;
        this.redisDataSerializer = makeSerializer(serializerType);
    }

    /**
     * 默认使用json序列化器
     *
     * @param expiration    缓存有效时间
     * @param preloadTime   缓存刷新时间
     * @param timeUnit      时间单位 {@link TimeUnit}
     * @param forceRefresh  是否强制刷新
     * @param magnification 非空值和null值之间的时间倍率
     */
    public SecondaryCacheSetting(long expiration, long preloadTime, TimeUnit timeUnit, boolean forceRefresh, int magnification) {
        this.expiration = expiration;
        this.preloadTime = preloadTime;
        this.timeUnit = timeUnit;
        this.forceRefresh = forceRefresh;
        this.magnification = magnification;
        this.usePrefix = true;
    }

    /**
     * @param expiration          缓存有效时间
     * @param preloadTime         缓存刷新时间
     * @param timeUnit            时间单位 {@link TimeUnit}
     * @param forceRefresh        是否强制刷新
     * @param allowNullValues     是否允许存NULL值，模式允许
     * @param magnification       非空值和null值之间的时间倍率
     * @param redisDataSerializer 默认序列化器
     */
    public SecondaryCacheSetting(long expiration, long preloadTime, TimeUnit timeUnit, boolean forceRefresh,
                                 boolean allowNullValues, int magnification, RedisDataSerializer redisDataSerializer) {
        this.expiration = expiration;
        this.preloadTime = preloadTime;
        this.timeUnit = timeUnit;
        this.forceRefresh = forceRefresh;
        this.magnification = magnification;
        this.usePrefix = true;
        this.redisDataSerializer = redisDataSerializer;
    }

    public long getExpiration() {
        return expiration;
    }

    public void setExpiration(long expiration) {
        this.expiration = expiration;
    }

    public long getPreloadTime() {
        return preloadTime;
    }

    public void setPreloadTime(long preloadTime) {
        this.preloadTime = preloadTime;
    }

    public TimeUnit getTimeUnit() {
        return timeUnit;
    }

    public void setTimeUnit(TimeUnit timeUnit) {
        this.timeUnit = timeUnit;
    }

    public boolean isForceRefresh() {
        return forceRefresh;
    }

    public void setForceRefresh(boolean forceRefresh) {
        this.forceRefresh = forceRefresh;
    }

    public boolean isUsePrefix() {
        return usePrefix;
    }

    public int getMagnification() {
        return magnification;
    }

    public void setMagnification(int magnification) {
        this.magnification = magnification;
    }

    public RedisDataSerializer getRedisDataSerializer() {
        return redisDataSerializer;
    }

    public void setRedisDataSerializer(RedisDataSerializer redisDataSerializer) {
        this.redisDataSerializer = redisDataSerializer;
    }

    private RedisDataSerializer makeSerializer(String serializerType) {
        if (!StringUtils.isEmpty(serializerType)) {
            try {
                return (RedisDataSerializer) InvokeService.getClass(serializerType).newInstance();
            } catch (Exception e) {
                logger.error("The custom serializer initialization failed; default serialization will be used:"+e.getMessage(),e);
            }
        }

        return this.redisDataSerializer;
    }
}
